import cv2
import mediapipe as mp
import win32api
import win32con
import time

mp_drawing = mp.solutions.drawing_utils
mp_hands = mp.solutions.hands
gesture_counter = 0
gesture_threshold = 10
previous_gesture = None

cap = cv2.VideoCapture(0)


def keybd_event(VK_CODE, key_event):
    VK_CODE = int(VK_CODE)
    win32api.keybd_event(VK_CODE, 0, key_event, 0)


def detect_gesture(results, image):
    image_height, image_width, _ = image.shape
    gesture = None

    if results.multi_hand_landmarks:
        for hand_landmarks, handedness in zip(results.multi_hand_landmarks, results.multi_handedness):
            thumb_tip = hand_landmarks.landmark[mp_hands.HandLandmark.THUMB_TIP]
            index_finger_tip = hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP]
            middle_finger_tip = hand_landmarks.landmark[mp_hands.HandLandmark.MIDDLE_FINGER_TIP]
            pinky_tip = hand_landmarks.landmark[mp_hands.HandLandmark.PINKY_TIP]
            pinky_mcp = hand_landmarks.landmark[mp_hands.HandLandmark.PINKY_MCP]
            thumb_ip = hand_landmarks.landmark[mp_hands.HandLandmark.THUMB_IP]
            thumb_mcp = hand_landmarks.landmark[mp_hands.HandLandmark.THUMB_MCP]
            ring_finger_tip = hand_landmarks.landmark[mp_hands.HandLandmark.RING_FINGER_TIP]
            # 计算各手指与掌心的距离
            distances = [
                thumb_tip.x,
                index_finger_tip.x,
                middle_finger_tip.x,
                ring_finger_tip.x,
                pinky_tip.x
            ]
            if handedness.classification[0].label == "Left":
                if index_finger_tip.y < middle_finger_tip.y:
                    if thumb_tip.x > thumb_mcp.x:
                        cv2.putText(image, "WD", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0),2)
                        gesture = 'wd'
                    elif pinky_tip.x < pinky_mcp.x:
                        cv2.putText(image, "WA", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                        gesture = 'wa'
                    cv2.putText(image, "W", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                elif thumb_tip.x > thumb_mcp.x:
                    cv2.putText(image, "D", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                    gesture = 'd'
                elif pinky_tip.x < pinky_mcp.x:
                    cv2.putText(image, "A", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                    gesture = 'a'
                elif all(distance > 0.2 for distance in distances):
                    cv2.putText(image, "S", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                    gesture = 's'
            elif handedness.classification[0].label == "Right":
                if index_finger_tip.y < middle_finger_tip.y:
                    if thumb_tip.x < thumb_mcp.x:
                        cv2.putText(image, "UpLeft", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0),2)
                        gesture = 'upleft'
                    elif pinky_tip.x > pinky_mcp.x:
                        cv2.putText(image, "UpRight", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                        gesture = 'upright'
                    cv2.putText(image, "UP", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                elif thumb_tip.x < thumb_mcp.x:
                    cv2.putText(image, "Left", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                    gesture = 'left'
                elif pinky_tip.x > pinky_mcp.x:
                    cv2.putText(image, "Right", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                    gesture = 'right'
                elif all(distance > 0.2 for distance in distances):
                    cv2.putText(image, "Down", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                    gesture = 'down'

            mp_drawing.draw_landmarks(
                image,
                hand_landmarks,
                mp_hands.HAND_CONNECTIONS,
                mp_drawing.DrawingSpec(color=(0, 0, 255), thickness=2, circle_radius=4),
                mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2))

    return gesture


def control_keyboard(gesture):
    global gesture_counter, previous_gesture

    if gesture == previous_gesture:
        gesture_counter += 1
    else:
        gesture_counter = 1

    if gesture_counter >= gesture_threshold:
        if gesture == 'left':
            keybd_event(37, 0x00)  # 键盘按下左
        elif gesture == 'right':
            keybd_event(39, 0x00)  # 键盘按下右
        elif gesture == 'up':
            keybd_event(38, 0x00)  # 键盘按下上
        elif gesture == 'down':
            keybd_event(40, 0x00)  # 键盘按下下
        elif gesture == 'w':
            keybd_event(87, 0x00)  # 键盘按下W
        elif gesture == 'a':
            keybd_event(65, 0x00)  # 键盘按下A
        elif gesture == 'd':
            keybd_event(68, 0x00)  # 键盘按下D
        elif gesture == 's':
            keybd_event(83, 0x00)  # 键盘按下S
        elif gesture == 'wd':
            keybd_event(68, 0x00)  # 键盘按下D
            keybd_event(87, 0x00)  # 键盘按下W
            time.sleep(0.4)
        elif gesture == 'wa':
            keybd_event(65, 0x00)  # 键盘按下A
            keybd_event(87, 0x00)  # 键盘按下W
            time.sleep(0.4)
        elif gesture == 'upleft':
            keybd_event(37, 0x00)  # 键盘按下左
            keybd_event(38, 0x00)  # 键盘按下上
            time.sleep(0.4)
        elif gesture == 'upright':
            keybd_event(39, 0x00)  # 键盘按下右
            keybd_event(38, 0x00)  # 键盘按下上
            time.sleep(0.4)

        # 等待一段时间
        time.sleep(0.5)

        # 模拟松开键
        if gesture == 'left':
            keybd_event(37, 0x02)  # 键盘松开左
        elif gesture == 'right':
            keybd_event(39, 0x02)  # 键盘松开右
        elif gesture == 'up':
            keybd_event(38, 0x02)  # 键盘松开上
        elif gesture == 'down':
            keybd_event(40, 0x02)  # 键盘松开下
        elif gesture == 'w':
            keybd_event(87, 0x02)  # 键盘松开W
        elif gesture == 'a':
            keybd_event(65, 0x02)  # 键盘松开A
        elif gesture == 'd':
            keybd_event(68, 0x02)  # 键盘松开D
        elif gesture == 's':
            keybd_event(83, 0x02)  # 键盘松开S
        elif gesture == 'wd':
            keybd_event(68, 0x02)  # 键盘松开D
            keybd_event(87, 0x02)  # 键盘松开W
        elif gesture == 'wa':
            keybd_event(65, 0x02)  # 键盘按下A
            keybd_event(87, 0x02)  # 键盘按下W
        elif gesture == 'upleft':
            keybd_event(38, 0x02)  # 键盘按下上
            keybd_event(37, 0x02)  # 键盘按下左
        elif gesture == 'upright':
            keybd_event(38, 0x02)  # 键盘按下上
            keybd_event(39, 0x02)  # 键盘按下右

        gesture_counter = 0  # 重置计数器

    previous_gesture = gesture


with mp_hands.Hands(
        static_image_mode=False,
        max_num_hands=2,  # 修改为检测两只手
        min_detection_confidence=0.5,
        min_tracking_confidence=0.5) as hands:
    while cap.isOpened():
        success, image = cap.read()
        if not success:
            print("无法读取摄像头")
            break

        image = cv2.flip(image, 1)
        image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        results = hands.process(image_rgb)

        # 检测左手和右手的手势
        left_gesture = detect_gesture(results, image)
        right_gesture = detect_gesture(results, image)

        # 根据左右手势执行键盘操作
        if left_gesture:
            control_keyboard(left_gesture)
        elif right_gesture:
            control_keyboard(right_gesture)

        cv2.imshow('Hand Gestures', image)

        if cv2.waitKey(5) & 0xFF == 27:
            break

cap.release()
cv2.destroyAllWindows()
